package com.biz.primus.ms.payment.channel.allinpay;

import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.model.payment.enums.PaymentType;
import com.biz.primus.model.payment.vo.req.*;
import com.biz.primus.ms.payment.channel.allinpay.config.AllinPayConfig;
import com.biz.primus.ms.payment.channel.allinpay.lang.DES;
import com.biz.primus.ms.payment.channel.allinpay.lang.SimpleSigner;
import com.biz.primus.ms.payment.channel.allinpay.req.*;

import static com.biz.primus.model.payment.enums.PaymentExceptionEnum.ILLEGAL_PARAMETER;

/**
 * 通联通讯方法工厂
 */
public class AllInPayPayFactory {


    public SimpleSigner newSigner() {
        return new SimpleSigner();
    }

    public AllInPayUnifiedOrder newUnifiedOrder(PaymentReqVo reqVo) {
        AllInPayUnifiedOrder unifiedOrder = new AllInPayUnifiedOrder();
        AssertUtils.notNull(reqVo.getTradeType(), ILLEGAL_PARAMETER, String.format("Unsupported all-in-pay paytype:%s", reqVo.getTradeType()));
        unifiedOrder.setPaytype(reqVo.getTradeType());
        AssertUtils.hasLength(reqVo.getNotifyUrl(), ILLEGAL_PARAMETER, "access to notify_url error");
        unifiedOrder.setNotify_url(reqVo.getNotifyUrl());
        AssertUtils.hasLength(reqVo.getSubject(), ILLEGAL_PARAMETER, "access to orderBody error");
        unifiedOrder.setBody(reqVo.getSubject());
        AssertUtils.hasLength(reqVo.getMchOrderNo(), ILLEGAL_PARAMETER, "access to orderCode error");
        unifiedOrder.setReqsn(reqVo.getMchOrderNo());
        AssertUtils.notNull(reqVo.getPayAmount(), ILLEGAL_PARAMETER, "access to payAmount error");
        unifiedOrder.setTrxamt(reqVo.getPayAmount());
        unifiedOrder.setAppid(AllinPayConfig.APP_ID);
        unifiedOrder.setCusid(AllinPayConfig.CUS_ID);
        unifiedOrder.setRemark(reqVo.getRemark());
        unifiedOrder.setValidtime(reqVo.getValidTime());
        PaymentType paymentType = reqVo.getPaymentType();
        if (paymentType == PaymentType.ALL_IN_PAY_JS_API) {
            AssertUtils.hasLength(reqVo.getSeller(), ILLEGAL_PARAMETER, "access to open_id or user_id error");
            unifiedOrder.setAcct(reqVo.getAcct());
        }
        return unifiedOrder;
    }

    public AllInPayRefund newOrderRefund(PaymentRefundReqVo reqVo) {
        AllInPayRefund allInPayRefund = new AllInPayRefund();
        AssertUtils.hasLength(reqVo.getRefundNo(), ILLEGAL_PARAMETER, "access to refundNo error");
        allInPayRefund.setOldreqsn(reqVo.getRefundNo());
        AssertUtils.hasLength(reqVo.getMchOrderNo(), ILLEGAL_PARAMETER, "access to orderCode error");
        allInPayRefund.setReqsn(reqVo.getMchOrderNo());
        AssertUtils.notNull(reqVo.getRefundAmount(), ILLEGAL_PARAMETER, "access to refund amount error");
        allInPayRefund.setTrxamt(reqVo.getRefundAmount());
        allInPayRefund.setAppid(AllinPayConfig.APP_ID);
        allInPayRefund.setCusid(AllinPayConfig.CUS_ID);
        return allInPayRefund;
    }

    public AllInPayQuery newQuery(PaymentRefundReqVo reqVo) {
        AllInPayQuery allInPayQuery = new AllInPayQuery();
        AssertUtils.hasLength(reqVo.getRefundNo(), ILLEGAL_PARAMETER, "access to refundNo error");
        allInPayQuery.setReqsn(reqVo.getRefundNo());
        allInPayQuery.setAppid(AllinPayConfig.APP_ID);
        allInPayQuery.setCusid(AllinPayConfig.CUS_ID);
        return allInPayQuery;
    }

    public AllInPayCancel newOrderCancel(PaymentCancelReqVo reqVo) {
        AllInPayCancel cancel = new AllInPayCancel();
        cancel.setAppid(AllinPayConfig.APP_ID);
        cancel.setCusid(AllinPayConfig.CUS_ID);
        AssertUtils.hasLength(reqVo.getOldReqSn(), ILLEGAL_PARAMETER, "access to origin orderCode error");
        cancel.setOldreqsn(reqVo.getOldReqSn());
        cancel.setOldtrxid(reqVo.getOldTrxId());
        AssertUtils.hasLength(reqVo.getOldReqSn(), ILLEGAL_PARAMETER, "access to sn error");
        cancel.setReqsn(reqVo.getReqSn());
        AssertUtils.notNull(reqVo.getOldReqSn(), ILLEGAL_PARAMETER, "access to amount error");
        cancel.setTrxamt(reqVo.getTrxAmt());
        return cancel;
    }

    public AllInPayH5PayReqVo newH5Pay(PaymentReqVo paymentReqVo) {
        AllInPayH5PayReqVo pay = new AllInPayH5PayReqVo();
        pay.setPickupUrl(paymentReqVo.getPickUpUrl());
        pay.setReceiveUrl(paymentReqVo.getNotifyUrl());
        pay.setMerchantId(AllinPayConfig.CUS_ID);
        pay.setMerchantUserId(paymentReqVo.getSeller());
        pay.setOrderNo(paymentReqVo.getMchOrderNo());
        pay.setOrderAmount(paymentReqVo.getPayAmount());
        pay.setOrderCurrency(0);
        String orderDate = DateUtil.getNowFmtDatetime("yyyyMMddHHmmss");
        pay.setOrderDatetime(orderDate);
        pay.setOrderExpireDatetime(15);
        pay.setProductName(paymentReqVo.getSubject());
        pay.setProductDesc(paymentReqVo.getBody());
        pay.setExt1("");
        pay.setExt2("");
        return pay;
    }

    public AllInPayCardPay newCardPay(PaymentReqVo paymentReqVo) {
        AllInPayCardPay cardPay = new AllInPayCardPay();
        cardPay.setApp_key(AllinPayConfig.APP_KEY);
        cardPay.setOrder_id(paymentReqVo.getMchOrderNo());
        cardPay.setMer_id(AllinPayConfig.CUS_ID);
        String timestamp = DateUtil.getNowFmtDatetime("yyyyMMddHHmmss");
        cardPay.setMer_tm(timestamp);
        cardPay.setTimestamp(timestamp);
        cardPay.setMer_order_id(paymentReqVo.getMchOrderNo());
        cardPay.setAmount(String.valueOf(paymentReqVo.getPayAmount()));
        cardPay.setCard_id(DES.encrypt(String.format("%saop%s", timestamp, paymentReqVo.getCardId()), AllinPayConfig.DES_SECRET));
        cardPay.setPassword(DES.encrypt(String.format("%saop%s", timestamp, paymentReqVo.getTradePassword()), AllinPayConfig.DES_SECRET));
        return cardPay;
    }

    public AllInPayCardAdd newAdd(AllInPayCardAddReqVo reqVo) {
        AllInPayCardAdd cardAdd = new AllInPayCardAdd();
        cardAdd.setApp_key(AllinPayConfig.APP_KEY);
        cardAdd.setTimestamp(DateUtil.getNowFmtDatetime("yyyyMMddHHmmss"));
        cardAdd.setOrder_id(reqVo.getTradNo());
        cardAdd.setCard_id(reqVo.getCardNo());
        cardAdd.setPrdt_no(AllinPayConfig.PRDT_NO);
        cardAdd.setAmount(String.valueOf(reqVo.getAmount()));
        cardAdd.setTop_up_way(String.valueOf(reqVo.getWay()));
        cardAdd.setOpr_id(reqVo.getOperator());
        cardAdd.setDesn(reqVo.getRemark());
        return cardAdd;
    }

    public AllInPayCardChange newChange(AllInPayCardChangeReqVo reqVo) {
        AllInPayCardChange change = new AllInPayCardChange();
        change.setApp_key(AllinPayConfig.APP_KEY);
        String timestamp = DateUtil.getNowFmtDatetime("yyyyMMddHHmmss");
        change.setTimestamp(timestamp);
        change.setCard_id(reqVo.getCardNo());
        change.setOrder_id(reqVo.getTradNo());
        String opDes = DES.encrypt(String.format("%saop%s", timestamp, reqVo.getOriginPwd()), AllinPayConfig.DES_SECRET);
        String npDes = DES.encrypt(String.format("%saop%s", timestamp, reqVo.getNewPwd()), AllinPayConfig.DES_SECRET);
        change.setNew_password(npDes);
        change.setPassword(opDes);
        return change;
    }

    public AllInPayCardOpen newOpen(AllInPayCardOpenReqVo reqVo) {
        AllInPayCardOpen cardOpen = new AllInPayCardOpen();
        cardOpen.setApp_key(AllinPayConfig.APP_KEY);
        cardOpen.setTimestamp(DateUtil.getNowFmtDatetime("yyyyMMddHHmmss"));
        cardOpen.setOrder_id(reqVo.getTradNo());
        cardOpen.setBrh_id(AllinPayConfig.BRH_ID);
        cardOpen.setBrand_no(AllinPayConfig.BRAND_NO);
        cardOpen.setPhone_num(reqVo.getMobile());
        cardOpen.setPassword(reqVo.getPwd());
        return cardOpen;
    }

    public AllInPayScanPay newScanPay(PaymentReqVo paymentReqVo) {
        AllInPayScanPay scanPay = new AllInPayScanPay();
        scanPay.setAppid(AllinPayConfig.APP_ID);
        scanPay.setCusid(AllinPayConfig.CUS_ID);
        scanPay.setTrxamt(paymentReqVo.getPayAmount());
        scanPay.setReqsn(paymentReqVo.getMchOrderNo());
        scanPay.setBody(paymentReqVo.getSubject());
        scanPay.setRemark(paymentReqVo.getRemark());
        scanPay.setAuthcode(paymentReqVo.getAuthCode());
        return scanPay;
    }

    public AllInPayCardRefund newCardBack(PaymentRefundReqVo reqVo) {
        AllInPayCardRefund cardRefund = new AllInPayCardRefund();
        cardRefund.setApp_key(AllinPayConfig.APP_KEY);
        cardRefund.setMer_id(AllinPayConfig.CUS_ID);
        cardRefund.setBack_order_id(reqVo.getRefundNo());
        String timestamp = DateUtil.getNowFmtDatetime("yyyyMMddHHmmss");
        String date = DateUtil.getNowFmtDatetime("yyyyMMdd");
        cardRefund.setTimestamp(timestamp);
        cardRefund.setOrder_id(reqVo.getMchOrderNo());
        cardRefund.setOri_order_id(reqVo.getOriOrderNo());
        cardRefund.setTrans_date(date);
        cardRefund.setAmount(reqVo.getRefundAmount());
        cardRefund.setMisc(reqVo.getRefundReason());
        return cardRefund;
    }

    public AllInPayCardRefundQuery newCardBackQuery(PaymentRefundReqVo reqVo) {
        AllInPayCardRefundQuery cardRefundQuery = new AllInPayCardRefundQuery();
        cardRefundQuery.setApp_key(AllinPayConfig.APP_KEY);
        cardRefundQuery.setMer_id(AllinPayConfig.CUS_ID);
        String timestamp = DateUtil.getNowFmtDatetime("yyyyMMddHHmmss");
        String date = DateUtil.getNowFmtDatetime("yyyyMMdd");
        cardRefundQuery.setTimestamp(timestamp);
        cardRefundQuery.setOrder_id(reqVo.getOrderNo());
        cardRefundQuery.setBack_order_id(reqVo.getRefundNo());
        cardRefundQuery.setTrans_date(date);
        return cardRefundQuery;
    }


    private static class AllInPayFactoryHolder {
        static AllInPayPayFactory instance = new AllInPayPayFactory();
    }

    private AllInPayPayFactory() {

    }

    public static AllInPayPayFactory newInstance() {
        return AllInPayFactoryHolder.instance;
    }

}
